package com.hjx.movie.core.system.service.admin.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hjx.movie.common.utils.ResultType;
import com.hjx.movie.common.utils.exceptions.CustomException;
import com.hjx.movie.common.utils.tree.TreeBuilder;
import com.hjx.movie.core.system.service.admin.IApiService;
import com.hjx.movie.core.system.service.admin.IRoleApiService;
import com.hjx.movie.core.system.vo.ApiTreeNode;
import com.hjx.movie.core.util.CombineBeansUtil;
import com.hjx.movie.core.util.cache.CacheKey;
import com.hjx.movie.core.util.cache.CacheUtil;
import com.hjx.movie.persistence.system.mapper.IvyApiMapper;
import com.hjx.movie.persistence.system.model.IvyApi;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>Title:</p>
 * <p>Description:</p>
 *
 * @author hjx
 * @date 2021/1/8 - 16:26
 */
@Slf4j
@Service
@Transactional
@CacheConfig(cacheNames = "IvyMovie:SpringCache:ApiCache",keyGenerator = "cacheKeyGenerator")
public class ApiService extends ServiceImpl<IvyApiMapper, IvyApi> implements IApiService {
    @Resource
    private CacheUtil<IvyApi> cacheUtil;

    public static final String API_KEY = CacheUtil.cacheNameFormat(CacheKey.SYSTEM.getName(),CacheKey.API.getName());
    public static final String API_CACHE_DATA = CacheUtil.cacheNameFormat(CacheKey.SYSTEM.getName(),CacheKey.API.getName(),CacheKey.PRE_SAVE_API.getName());

    @Resource
    private IRoleApiService roleApiService;

    @Override
    @Cacheable(unless = "#result==null")
    public List<ApiTreeNode> selectApiTree(Long rootApiId, String apiNameLike, Boolean apiStatus) {
        if (rootApiId!=null){
            // 从预热的缓存中取出数据
            List<IvyApi> cacheApis = cacheUtil.getCacheList(API_CACHE_DATA);
            List<IvyApi> ivyApis =  cacheApis.stream().filter(
                    item -> {
                        boolean flag = false;
                        if (item.getApiId().equals(rootApiId) || item.getApiPids().contains(rootApiId.toString())) {
                            flag = true;
                            if (StringUtils.isNotBlank(apiNameLike)) {
                                flag = item.getApiName().contains(apiNameLike);
                            }
                            if (apiStatus!=null&&flag){
                                flag = item.getStatus()==apiStatus;
                            }
                        }
                        return flag;
                    }
            ).collect(Collectors.toList());

//            List<IvyApi> ivyApis = getBaseMapper().selectApiTree(rootApiId, apiNameLike, apiStatus);
            //将List<IvyApi>转换为List<ApiTreeNode>
            List<ApiTreeNode> apiTreeNodes = ivyApis.stream().map(item->{
                ApiTreeNode node = new ApiTreeNode();
                BeanUtils.copyProperties(item,node);
                return node;
            }).collect(Collectors.toList());
            //如果使用条件查询 会破坏树形结构所以不以树形返回
            if (StringUtils.isNotBlank(apiNameLike)||apiStatus!=null){
                return apiTreeNodes;
            }else {
                return TreeBuilder.builderTreeWidth(apiTreeNodes,rootApiId);
            }
        }else {
            throw new CustomException(ResultType.USER_INPUT_ERROR,"查询参数的接口id不能为空");
        }
    }
    @CacheEvict(value = "IvyMovie:SpringCache:ApiCache",allEntries=true)
    @Override
    public boolean addApi(IvyApi api) {
        IvyApi parent = cacheUtil.getCacheData(API_CACHE_DATA,api.getApiPid().toString());
//        IvyApi parent = this.getById(api.getApiPid());
        Assert.notNull(parent,"找不到此父节点");
        // 将父节点设置为非叶子节点
        parent.setIsLeaf(false);
        api.setIsLeaf(true);
        // 设置层级
        api.setLevel(parent.getLevel()+1);
        // 设置所有的"父节点"信息
        api.setApiPids(parent.getApiPids()+",["+api.getApiPid()+"]");
        api.setStatus(api.getStatus() == null || api.getStatus());
        boolean result = this.updateById(parent)&&this.save(api);
        // 新增同时要修改预热的缓存数据
        if (result){
            cacheUtil.getOpsForHash().put(API_CACHE_DATA,parent.getApiId().toString(),parent);
            cacheUtil.getOpsForHash().put(API_CACHE_DATA,api.getApiId().toString(),api);
        }
        log.debug("新增接口的ApiId为:{}",api.getApiId());
        return result;

    }

    @CacheEvict(value = "IvyMovie:SpringCache:ApiCache",allEntries=true)
    @Override
    public boolean deleteApi(Long apiId) {
        // 查询出要删除的节点信息
//        IvyApi api = getById(apiId);
        IvyApi api = cacheUtil.getCacheData(API_CACHE_DATA,apiId.toString());
        Assert.notNull(api,"查询不到需要删除的接口信息");
        Assert.notNull(api.getApiPid(),"父节点字段不能为空");
//        QueryWrapper<IvyApi> wrapper = new QueryWrapper<>();
        // 判断自己是不是父节点
//        List<IvyApi> list = list(wrapper.like("api_pids","["+apiId+"]"));
        boolean listResult = cacheUtil.getCacheList(API_CACHE_DATA).stream()
                .anyMatch(item -> item.getApiPids().contains(apiId.toString()));

        if (listResult){
            throw new CustomException(ResultType.USER_INPUT_ERROR,"不能删除有子接口的父级接口");
        }
//        wrapper.clear();
        // 查询父节点有几个子节点
//        List<IvyApi> fatherChildren = list(wrapper.like("api_pids","["+api.getApiPid()+"]"));
        boolean fatherChildren = cacheUtil.getCacheList(API_CACHE_DATA)
                .stream()
                .filter(item -> item.getApiPids().contains(api.getApiPid().toString()))
                .count()==1;
        boolean result;
        if (fatherChildren){
            // 进行删除 并且将父节点设置为叶子
            //删除同时要修改预热的缓存数据
            IvyApi parent = cacheUtil.getCacheData(API_CACHE_DATA,api.getApiPid().toString());
            parent.setIsLeaf(true);
            result = removeById(apiId)&&updateById(parent);
            if (result){
                cacheUtil.getOpsForHash().put(API_CACHE_DATA,parent.getApiId().toString(),parent);
                cacheUtil.getOpsForHash().delete(API_CACHE_DATA,apiId.toString());
            }
        }else {
            result =removeById(apiId);
            if (result){
                cacheUtil.getOpsForHash().delete(API_CACHE_DATA,apiId.toString());
            }
        }
        return result;
    }

    @CacheEvict(value = "IvyMovie:SpringCache:ApiCache",allEntries=true)
    @Override
    public boolean updateApi(IvyApi api) {
        // 修改同时要修改预热的缓存数据
        Assert.notNull(api.getApiId(),"修改操作必须带主键");
        if (updateById(api)){
            IvyApi cacheData = cacheUtil.getCacheData(API_CACHE_DATA,api.getApiId().toString());
            CombineBeansUtil.combineBean(api,cacheData);
            log.debug("{}",cacheData);
            cacheUtil.getOpsForHash().put(API_CACHE_DATA,api.getApiId().toString(),cacheData);
            return true;
        }
        return false;
    }

    @Cacheable(unless = "#result==null")
    @Override
    public List<Long> findApiExpandedKeys() {
        List<IvyApi> cacheList = cacheUtil.getCacheList(API_CACHE_DATA);
        return cacheList.stream().filter(
                item -> item.getLevel().equals(1) || item.getLevel().equals(2)
        ).map(IvyApi::getApiId).collect(Collectors.toList());
    }

    @Override
    public List<Long> findApiCheckedKeys(Long roleId) {
        return roleApiService.findApiByRoleId(roleId);
    }


}
